package com.binance.rabbitmq.autoconfigure;

import com.binance.rabbitmq.config.DefaultConfig;
import com.binance.rabbitmq.config.RabbitConfig;
import com.binance.rabbitmq.policy.RecovererPolicy;
import com.binance.rabbitmq.policy.impl.DeadLetterRecovererPolicy;
import com.binance.rabbitmq.processor.CorrelationPostProcessor;
import com.binance.rabbitmq.processor.DefaultCorrelationDataPostProcessor;
import com.binance.rabbitmq.processor.DefaultCorrelationPostProcessor;
import com.binance.rabbitmq.processor.InfoHeaderMessagePostProcessor;
import com.binance.rabbitmq.recoverer.DelayMessageRecoverer;
import com.binance.rabbitmq.recoverer.MessageExceptionHandler;
import com.binance.rabbitmq.recoverer.impl.LogMessageExceptionHandler;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.CorrelationDataPostProcessor;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;

/**
 * Created by robin.wu on 2018/11/29.
 */
@Configuration
@PropertySource(value = "classpath:rabbitmq-default.properties")
@ConditionalOnProperty(prefix = "rabbitmq.auto-config", name = "enabled", matchIfMissing = true)
public class RabbitMqConfiguration {

    @Bean
    public DefaultConfig defaultConfig(){
        return new DefaultConfig();
    }

    @Bean
    public RabbitConfig rabbitExtConfig() {
        return new RabbitConfig();
    }

    @Bean
    @ConditionalOnMissingBean(RabbitAdmin.class)
    public RabbitAdmin rabbitAdmin(CachingConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    @Bean
    @Primary
//    @ConditionalOnMissingBean(MessageConverter.class)
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    @ConditionalOnMissingBean(MessageRecoverer.class)
    public MessageRecoverer messageRecoverer() {
        return new DelayMessageRecoverer();
    }

    @Bean
    public MessagePostProcessor headerMessagePostProcessor(RabbitConfig rabbitConfig) {
        InfoHeaderMessagePostProcessor infoHeaderMessagePostProcessor = new InfoHeaderMessagePostProcessor();
        infoHeaderMessagePostProcessor.setHeaders(rabbitConfig.getInfoHeaders());
        return infoHeaderMessagePostProcessor;
    }

    @Bean
    @ConditionalOnMissingBean(CorrelationDataPostProcessor.class)
    public CorrelationDataPostProcessor correlationDataPostProcessor(CorrelationPostProcessor correlationPostProcessor) {
        return new DefaultCorrelationDataPostProcessor(correlationPostProcessor);
    }

    @Bean
    @ConditionalOnMissingBean(CorrelationPostProcessor.class)
    public CorrelationPostProcessor correlationPostProcessor() {
        return new DefaultCorrelationPostProcessor();
    }

    @Bean
    @ConditionalOnMissingBean(DeadLetterRecovererPolicy.class)
    public RecovererPolicy DeadLetterRecovererPolicy(){
        return new DeadLetterRecovererPolicy();
    }

    @Bean
    @ConditionalOnMissingBean(LogMessageExceptionHandler.class)
    public MessageExceptionHandler logMessageExceptionHandler(){
        return new LogMessageExceptionHandler();
    }
}
